﻿package net.wangit.jdbc.executable;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import net.wangit.context.ActionContext;
import net.wangit.jdbc.ColumnRow;
import net.wangit.jdbc.DB;
import net.wangit.jdbc.DBImplementor;
import net.wangit.jdbc.JDBCException;
import net.wangit.jdbc.database.Database;
import net.wangit.jdbc.table.Column;
import net.wangit.jdbc.table.TableConfigurationException;
import net.wangit.jdbc.table.TableMeta;
import net.wangit.jdbc.table.TableMetaFactory;
import net.wangit.jdbc.util.JDBCExceptionReporter;
import net.wangit.util.Checker;
import net.wangit.view.unit.UnitConfigurationException;


public class VersionChecker {

	private VersionChecker() {
	}

	public static boolean isDirty(DB db, ActionContext ac, String domain,
			String tableName, String unitId) throws JDBCException {
		TableMeta meta = TableMetaFactory.getTableMeta(domain, tableName);
		Column versionColumn = meta.getVersionColumn();
		if (versionColumn == null) {
			throw new TableConfigurationException((new StringBuilder(
					"VersionColumn not found: ")).append(domain).append("/")
					.append(tableName).toString());
		}
		String versionValue[] = ac.getRequestParameters((new StringBuilder(
				String.valueOf(unitId))).append(".").append(
				versionColumn.getName()).append(".v").toString());
		if (versionValue == null)
			throw new UnitConfigurationException((new StringBuilder(
					"VersionColumn's value(s) not found: ")).append(domain)
					.append("/").append(unitId).toString());
		List<Column> primaryKeyColumns = meta.getPrimaryKey().getColumns();
		ColumnRow row = new UpdateRow();
		for (int i = 0; i < versionValue.length; i++) {
			for (int j = 0; j < primaryKeyColumns.size(); j++) {
				Column column = primaryKeyColumns.get(j);
				String value = ac.getRequestParameter(i, (new StringBuilder(
						String.valueOf(unitId))).append(".").append(
						column.getName()).append(".k").toString());
				row.setPrimaryKey(column.getName(), value);
			}

			if (isDirty((DBImplementor) db, tableName, primaryKeyColumns, row,
					versionColumn, versionValue[i]))
				return true;
		}

		return false;
	}

	public static boolean isDirty(DBImplementor db, String tableName,
			List<Column> primaryKeyColumns, ColumnRow row,
			Column versionColumn, String versionValue) throws JDBCException {
		String sql;
		if (Checker.isEmpty(versionValue))
			return false;
		sql = toVersionStatement(tableName, primaryKeyColumns, versionColumn);
		java.sql.PreparedStatement st;
		ResultSet rs = null;
		boolean flag = false;
		Database database = db.getJDBCSettings().getDatabase();
		try {
			st = db.getBatcher().prepareQueryStatement(sql, false);
			for (int i = 0; i < primaryKeyColumns.size(); i++) {
				Column column = primaryKeyColumns.get(i);
				String value = row.getPrimaryKey(column.getName());
				column.getSqlType(database).set(st, value, i + 1);
			}

			if (!primaryKeyColumns.contains(versionColumn))
				versionColumn.getSqlType(database).set(st, versionValue,
						primaryKeyColumns.size() + 1);
			try {
				rs = db.getBatcher().getResultSet(st);
				flag = rs == null || !rs.next();
			} catch (SQLException sqle) {
				JDBCExceptionReporter.logExceptions(sqle);
				throw new JDBCException("query error", sqle);
			} finally {
				db.getBatcher().closeQueryStatement(st, rs);
			}
		} catch (SQLException e) {
			throw new JDBCException(e.getMessage());
		}
		return flag;
	}

	private static String toVersionStatement(String tableName,
			List<Column> primaryKeyColumns, Column versionColumn) {
		StringBuffer buf = new StringBuffer("select * from ");
		buf.append(tableName).append(" where ");
		Iterator<Column> iter = primaryKeyColumns.iterator();
		while (iter.hasNext()) {
			Column column = iter.next();
			buf.append(column.getName()).append("=?");
			if (iter.hasNext())
				buf.append(" and ");
		}

		if (!primaryKeyColumns.contains(versionColumn))
			buf.append(" and ").append(versionColumn.getName()).append("=?");
		return buf.toString();
	}
}
